package com.lagou.edu.lagouframework.servlet;

import com.lagou.edu.lagouframework.annotations.*;
import com.lagou.edu.lagouframework.pojo.Handler;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.URL;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author xq
 * @description servlet
 * @date 2021/05/18 19:51:03
 **/
public class LagouDispactorServlet extends HttpServlet {

    private Properties properties = new Properties();

    private List<String> classNames = new ArrayList<>();

    private Map<String, Object> ioc = new HashMap<>();

    private List<Handler> handlerMapping = new ArrayList<>();

    private List<String> authList = new ArrayList<>();


    @Override

    public void init(ServletConfig config) throws ServletException {
        //1.加载properties配置文件
        String contextConfigLocation = config.getInitParameter("contextConfigLocation");
        doLoadConfig(contextConfigLocation);

        //2.扫描包获取类路径
        doScan(properties.getProperty("scanPackage"));

        //3.实例化IoC容器
        doInitBean();

        //4.实例化注入
        doAutoWired();

        //5.处理映射器HandlerMapping
        doHandlerMapping();

        System.out.println("初始化完成");

        //6.处理

        //处理请求
    }

    private void doHandlerMapping() {
        if (ioc.isEmpty()) return;

        for (Map.Entry<String, Object> entry : ioc.entrySet()) {
            Object o = entry.getValue();
            //只处理controller的mapping
            Class<?> aClass = o.getClass();
            //不是controller或者需要权限访问的的LagouSecurity都不做处理器映射器
            if (!aClass.isAnnotationPresent(LagouController.class) || !aClass.isAnnotationPresent(LagouSecurity.class)) continue;
            //获取权限注解
            LagouSecurity lagouSecurity = aClass.getAnnotation(LagouSecurity.class);
            String[] value = lagouSecurity.value();
            authList= Arrays.asList(value);
            //获取RequestMapping的值
            LagouRequestMapping annotation = aClass.getAnnotation(LagouRequestMapping.class);
            String baseUrl = annotation.value();//  /demo
            //处理方法上的注解
            Method[] methods = aClass.getMethods();
            for (int i = 0; i < methods.length; i++) {
                Method method = methods[i];
                if (method.isAnnotationPresent(LagouRequestMapping.class)) {
                    LagouRequestMapping methodAnnotation = method.getAnnotation(LagouRequestMapping.class);
                    String uri = methodAnnotation.value();
                    String URI = baseUrl + uri;

                    Handler handler = new Handler(entry.getValue(), method, Pattern.compile(URI));

                    Parameter[] parameters = method.getParameters();
                    for (int j = 0; j < parameters.length; j++) {
                        Parameter parameter = parameters[j];
                        if (parameter.getType() == HttpServletRequest.class || parameter.getType() == HttpServletResponse.class) {
                            handler.getIndexMapping().put(parameter.getType().getSimpleName(), j);
                        } else {
                            handler.getIndexMapping().put(parameter.getName(), j);
                        }
                    }


                    handlerMapping.add(handler);

                }
            }


        }
    }


    //初始化bean
    private void doInitBean() {
        if (classNames.size() == 0) return;

        try {
            for (String className : classNames) {
                Class<?> aClass = Class.forName(className);
                //判断是否是LagouController的注释
                if (aClass.isAnnotationPresent(LagouController.class)) {
                    String simpleName = aClass.getSimpleName();
                    String upNameToLower = transUpNameToLower(simpleName);
                    ioc.put(upNameToLower, aClass.newInstance());
                }

                if (aClass.isAnnotationPresent(LagouService.class)) {
                    LagouService annotation = aClass.getAnnotation(LagouService.class);
                    String value = annotation.value();
                    if (!"".equals(value)) {
                        ioc.put(value, aClass.newInstance());
                    } else {
                        String serviceName = transUpNameToLower(aClass.getSimpleName());
                        ioc.put(serviceName, aClass.newInstance());
                    }

                    //service有可能有多个interface
                    Class<?>[] interfaces = aClass.getInterfaces();
                    for (int i = 0; i < interfaces.length; i++) {
                        Class<?> anInterface = interfaces[i];
                        ioc.put(anInterface.getName(), aClass.newInstance());
                    }


                }

            }


        } catch (Exception e) {
            e.printStackTrace();
        }


    }


    private String transUpNameToLower(String simpleName) {
        char[] chars = simpleName.toCharArray();
        if ('A' <= chars[0] && chars[0] <= 'Z') {
            chars[0] += 32;
        }
        return String.copyValueOf(chars);
    }

    //属性值注入
    private void doAutoWired() {
        if (ioc.isEmpty()) return;

        for (Map.Entry<String, Object> entry : ioc.entrySet()) {
            Object value = entry.getValue();
            Class<?> aClass = value.getClass();
            Field[] declaredFields = aClass.getDeclaredFields();
            for (int i = 0; i < declaredFields.length; i++) {
                Field declaredField = declaredFields[i];
                if (declaredField.isAnnotationPresent(LagouAutowired.class)) {
                    LagouAutowired annotation = declaredField.getAnnotation(LagouAutowired.class);
                    String beanName = annotation.value();
                    if ("".equals(beanName)) {
                        beanName = declaredField.getType().getName();
                    }

                    //设置可以赋值
                    declaredField.setAccessible(true);


                    try {
                        declaredField.set(entry.getValue(), ioc.get(beanName));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }


                }
            }
        }




    }

    private void doLoadConfig(String contextConfigLocation) {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
        try {
            properties.load(resourceAsStream);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    //scanPath com.lagou.edu.demo
    private void doScan(String scanPath) {
        //获取类的全路径
        String filePath = Thread.currentThread().getContextClassLoader().getResource("").getPath() + scanPath.replace(".", "/");
        File scanfile = new File(filePath);
        File[] files = scanfile.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {//相当于com.lagou.edu.demo.controller
                doScan(scanPath + "." + file.getName());
            } else if (file.getName().endsWith(".class")) {
                String classPath = scanPath + "." + file.getName().replace(".class", "");
                classNames.add(classPath);
            }
        }

    }


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //处理请求信息
        String url = req.getRequestURI();
        Handler handler = getReq(url);
        if (handler == null) {
            resp.getWriter().write("404 bad request");
            return;
        }

        Parameter[] parameters = handler.getMethod().getParameters();
        Object[] paraValues = new Object[parameters.length];

        Map<String, String[]> parameterMap = req.getParameterMap();
        if (parameterMap.isEmpty()) {
            resp.setHeader("Content-type", "text/html;charset=UTF-8");
            resp.setCharacterEncoding("UTF-8");
            resp.getWriter().write("请输入用户编号");
            return;
        }


        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            String value = StringUtils.join(entry.getValue(), ",");
            if (!handler.getIndexMapping().containsKey(entry.getKey())) {
                continue;
            }


            if (entry.getKey().equals("name")) {
                if (!authList.contains(value)) {
                    resp.setHeader("Content-type", "text/html;charset=UTF-8");
                    resp.setCharacterEncoding("UTF-8");
                    resp.getWriter().write("您还没有注册,没有继续访问的权限");
                    return;
                }
            }


            Integer index = handler.getIndexMapping().get(entry.getKey());
            paraValues[index] = value;


        }

        Integer requestIndex = handler.getIndexMapping().get(HttpServletRequest.class.getSimpleName());
        paraValues[requestIndex] = req;

        Integer reposeIndex = handler.getIndexMapping().get(HttpServletResponse.class.getSimpleName());
        paraValues[reposeIndex] = resp;


        try {
            handler.getMethod().invoke(handler.getController(), paraValues);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private Handler getReq(String url) {
        for (Handler handler : handlerMapping) {
            Matcher matcher = handler.getPattern().matcher(url);
            if (matcher.matches()) {
                return handler;
            }
        }
        return null;
    }


}
